﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Drawing.Printing;

namespace Preyla
{
    public partial class FormMain : Form
    {
        int Rights = 0;

        IDatabase DBManager = new AccessManager(Properties.Settings.Default.ConnectionString);

        int ConfigurationID = 0;

        Bitmap print;

        int IterationCount = 0;

        BufferedGraphicsContext currentContext;
        BufferedGraphics ImageBuffer;

        public FormMain()
        {
            InitializeComponent();

            currentContext = BufferedGraphicsManager.Current;

            try
            {
                ImageBuffer = currentContext.Allocate(ImagePanel.CreateGraphics(), Rectangle.FromLTRB(0, 0, 50000, 2000));

                ImageBuffer.Graphics.FillRectangle(new SolidBrush(Color.White), Rectangle.FromLTRB(0, 0, 50000, 2000));
            }
            catch (Exception ex)
            {
                ImageBuffer = currentContext.Allocate(ImagePanel.CreateGraphics(), Rectangle.FromLTRB(0, 0, 2000, 1000));

                ImageBuffer.Graphics.FillRectangle(new SolidBrush(Color.White), Rectangle.FromLTRB(0, 0, 2000, 1000));  
            }
        }

        private void ComponentButton_Click(object sender, EventArgs e)
        {
            FormComponent formComponent = new FormComponent();

            Thread.Sleep(100);

            formComponent.ShowDialog();
        }

        private void AboutButton_Click(object sender, EventArgs e)
        {
            FormAbout formAbout = new FormAbout();

            formAbout.ShowDialog();
        }

        private void ServersButton_Click(object sender, EventArgs e)
        {
            FormServers formServers = new FormServers(Rights);

            Thread.Sleep(100);

            formServers.ShowDialog();

            if (formServers.GetConfigurationID != 0)
            {
                ConfigurationID = formServers.GetConfigurationID;

                IterationCount = 0;

                try
                {
                    if (!Analysis()) return;

                    DrawImage();

                    LogoImage.Visible = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);

                    if (DBManager.IsOpen())
                        DBManager.Close();
                }                
            }
        }

        bool CalcMTBF(int ConfigurationID, out double MTBF, out double MTTR)
        {
            IterationCount++;

            if (IterationCount > 100)
            {
                throw new Exception("Bad configuration. There are loops in components");
            }

            string[][] Components = DBManager.ExecuteReader("SELECT Components.ID, Components.[Name], Components.MTBF, Components.MTTR, Links.Duplication FROM Objects Components, Links WHERE Components.ID = Links.ObjectID AND Links.ID = " + ConfigurationID);

            if (Components.Length == 0)
            {
                MTBF = 0.0;
                MTTR = 0.0;
                
                return true;
            }

            double Sum_1_MTBF = 0.0;
            double Sum_Md = 0.0;
            double Sum_MTTR = 0.0;

            for (int i = 0; i < Components.Length; i++)
            {
                //double MTBF_;
                //double MTTR_;
                //int Duplication_;

                if (CalcMTBF(Int32.Parse(Components[i][0]), out MTBF, out MTTR))
                {
                    MTBF = double.Parse(Components[i][2]) / 24.0 / 365.0;
                    MTTR = double.Parse(Components[i][3]);                    
                }

                int Duplication = Int32.Parse(Components[i][4]);

                double MTBFYears = MTBF;
                double _1_MTBF = 1.0 / MTBFYears;
                double Md = (Duplication == 1) ? _1_MTBF : (Duplication * Math.Pow(_1_MTBF, Duplication) * (MTTR / 24.0 / 365.0));

                Sum_MTTR += MTTR;                

                Sum_1_MTBF += _1_MTBF;
                Sum_Md += Md;
            }

            double Ps = Sum_Md;
            double MTBFs = 1 / Ps;
            double T = Sum_MTTR / Components.Length;
            double MTTRs = Ps * T;
            //double Ks = MTBFs / (MTBFs + MTTRs / 24.0 / 365.0);

            MTBF = MTBFs;
            MTTR = T;
            //Duplication = 0;

            return false;
        }

        bool Analysis()
        {
            DBManager.Open();

            string[][] Data = DBManager.ExecuteReader("SELECT Components.ID, Components.[Name], Components.MTBF, Components.MTTR, Links.Duplication FROM Objects Components, Links WHERE Components.ID = Links.ObjectID AND Links.ID = " + ConfigurationID);

            if (Data.Length == 0)
            {
                MessageBox.Show("Configuration is empty");

                DBManager.Close();

                return false;
            }

            double Sum_1_MTBF = 0.0;
            double Sum_1_MTBFfact = 0.0;
            double Sum_1_MTBFavg = 0.0;
            double Sum_Md = 0.0;
            double Sum_MTTR = 0.0;

            AnalysisTable.Rows.Clear();

            for (int i = 0; i < Data.Length; i++)
            {
                double MTBFyears;
                double MTTR;
                if (CalcMTBF(Int32.Parse(Data[i][0]), out MTBFyears, out MTTR))
                {
                    try
                    {
                        MTBFyears = Int32.Parse(Data[i][2]) / 365.0 / 24.0;
                        MTTR = Int32.Parse(Data[i][3]);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("One of configurations is empty");
                    }
                }
                
                double MTBFhours = MTBFyears * 24.0 * 365.0;                
                double _1_MTBF = 1.0 / MTBFyears;
                double _1_MTBFfact = _1_MTBF * 0.5;
                double _1_MTBFavg = _1_MTBF * 0.75;
                
                Sum_MTTR += MTTR;
                int Duplication = Int32.Parse(Data[i][4]);
                double Md = (Duplication == 1) ? _1_MTBF : (Duplication * Math.Pow(_1_MTBF, Duplication) * (MTTR / 24.0 / 365.0));

                AnalysisTable.Rows.Add();
                AnalysisTable[0, AnalysisTable.Rows.Count - 1].Value = Data[i][0];
                AnalysisTable[1, AnalysisTable.Rows.Count - 1].Value = Data[i][1];
                AnalysisTable[2, AnalysisTable.Rows.Count - 1].Value = Math.Round(MTBFhours, 0);
                AnalysisTable[3, AnalysisTable.Rows.Count - 1].Value = Math.Round(MTBFyears, 1);
                AnalysisTable[4, AnalysisTable.Rows.Count - 1].Value = Math.Round(MTTR, 0);
                AnalysisTable[5, AnalysisTable.Rows.Count - 1].Value = Math.Round(_1_MTBF, 3);
                AnalysisTable[6, AnalysisTable.Rows.Count - 1].Value = Math.Round(_1_MTBFfact, 3);
                AnalysisTable[7, AnalysisTable.Rows.Count - 1].Value = Math.Round(_1_MTBFavg, 3);
                AnalysisTable[8, AnalysisTable.Rows.Count - 1].Value = Duplication;
                AnalysisTable[9, AnalysisTable.Rows.Count - 1].Value = Md.ToString("0.000000");

                Sum_1_MTBF += _1_MTBF;
                Sum_1_MTBFfact += _1_MTBFfact;
                Sum_1_MTBFavg += _1_MTBFavg;
                Sum_Md += Md;
            }

            AnalysisTable.Rows.Add();
            AnalysisTable[1, AnalysisTable.Rows.Count - 1].Value = "Total:";
            AnalysisTable[5, AnalysisTable.Rows.Count - 1].Value = Math.Round(Sum_1_MTBF, 3);
            AnalysisTable[6, AnalysisTable.Rows.Count - 1].Value = Math.Round(Sum_1_MTBFfact, 3);
            AnalysisTable[7, AnalysisTable.Rows.Count - 1].Value = Math.Round(Sum_1_MTBFavg, 3);
            AnalysisTable[9, AnalysisTable.Rows.Count - 1].Value = Sum_Md.ToString("0.000000");

            for (int i = 0; i < 10; i++)
            {
                AnalysisTable[i, AnalysisTable.Rows.Count - 1].Style.BackColor = Color.LightGray;
            }

            double Ps = Sum_Md;// Sum_1_MTBF;
            double MTBFs = 1 / Ps;
            double T = Sum_MTTR / Data.Length;
            double MTTRs = Ps * T;
            double Ks = MTBFs / (MTBFs + MTTRs / 24.0 / 365.0);

            ParametersTable.Rows.Clear();

            ParametersTable.Rows.Add();
            ParametersTable[0, 0].Value = Sum_Md.ToString("0.000000");
            ParametersTable[1, 0].Value = (1.0 / Sum_Md).ToString("0.0");
            ParametersTable[2, 0].Value = Math.Round(T, 1);
            ParametersTable[3, 0].Value = Math.Round(MTTRs, 1);
            ParametersTable[4, 0].Value = Math.Round(Ks * 100, 4) + "%";

            DBManager.Close();

            return true;
        }

        private void DrawImage()
        {
            Size size;

            int Top = 40;
            int Left = 20;

            Graphics g = ImageBuffer.Graphics;

            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            g.FillRectangle(new SolidBrush(Color.White), ImagePanel.DisplayRectangle);

            Draw(ConfigurationID, 0, 0, Left, Top, g, out size);

            ImagePanel.Width = Math.Max(size.Width + 50, ImageCanvas.Width);
            ImagePanel.Height = Math.Max(size.Height + 50, ImageCanvas.Height);
 
            if (size.Width == 0 || size.Height == 0)
            {
                return;
            }

            ImageBuffer.Render();
            ImageBuffer.Render(ImagePanel.CreateGraphics());
        }

        bool Draw(int ComponentID, int ParentID, int LinkID, int Left, int Top, Graphics g, out Size size)
        {
            Size blocksize;

            int MaxDuplication = 0;
            int Width = 0;
            int Height = 0;
            int Margin = 5;

            Font font11 = new Font("Book Antiqua", 11.0f);
            Font font14 = new Font("Book Antiqua", 14.0f);

            if (!DBManager.IsOpen())
                DBManager.Open();

            string[][] Data = DBManager.ExecuteReader("SELECT Components.ID, Components.[Name], Components.[Image], Links.Duplication, Links.LinkID FROM Objects Components, Links WHERE Components.ID = Links.ObjectID AND Links.ID = " + ComponentID);

            if (Data.Length == 0)
            {
                string[][] Component = DBManager.ExecuteReader("SELECT Components.ID, Components.[Name], Components.[Image], Links.Duplication FROM Objects Components, Links WHERE Components.ID = Links.ObjectID AND Components.ID = " + ComponentID + " AND Links.ID = " + ParentID + " AND LinkID = " + LinkID);

                int Duplication = Int32.Parse(Component[0][3]);

                for (int j = 0; j < Duplication; j++)
                {
                    g.DrawImage(Image.FromFile("Images\\" + Component[0][2]), new Point(Left + Margin + 64 * j, Top + Height));
                }

                SizeF sizef11 = g.MeasureString(Component[0][1], font11);

                g.DrawString(Component[0][1], font11, new SolidBrush(Color.Black), new PointF(Left + Margin + 64 * Duplication + Margin, Top + Height + Margin + 3));

                MaxDuplication = Math.Max(MaxDuplication, Duplication);
                Width = Math.Max(Width, Margin + 64 * Duplication + 3*Margin + (int)sizef11.Width);

                Height += 48;

                size = new Size(Width, Height);
                //g.FillRectangle(new SolidBrush(Color.FromArgb(50, 255, 0, 0)), Left, Top, size.Width, size.Height);

                return true;
            }

            string[][] ConfigurationName = DBManager.ExecuteReader("SELECT [Name] FROM Objects WHERE ID = " + ComponentID);

            SizeF sizef14 = g.MeasureString(ConfigurationName[0][0], font14);

            g.DrawString(ConfigurationName[0][0], font14, new SolidBrush(Color.Black), new PointF(Left + Margin, Top + Margin));

            Height = 2 * Margin + (int)sizef14.Height + Margin;
            Width = Margin + (int)sizef14.Width;

            for (int i = 0; i < Data.Length; i++)
            {
                int W = 0, H = 0;

                for (int j = 0; j < Int32.Parse(Data[i][3]); j++)
                {
                    if (Draw(Int32.Parse(Data[i][0]), ComponentID, Int32.Parse(Data[i][4]), Left + Margin + W, Top + Height + Margin, g, out blocksize))
                    {
                        W += blocksize.Width;
                        H = blocksize.Height;

                        break;
                    }
                    else
                    {
                        W += blocksize.Width;
                        H = blocksize.Height;
                    }
                }

                Width = Math.Max(Width, W);

                Height += 1 * Margin + H;
            }

            Height += 2 * Margin;

            if (DBManager.IsOpen())
                DBManager.Close();
            
            g.DrawRectangle(new Pen(Color.Black, 1.0f), new Rectangle(Left, Top + 2 * Margin + (int)sizef14.Height, Width, Height - 1*(2 * Margin + (int)sizef14.Height)));
            
            size = new Size(Width + 2 * Margin, Height);

            //g.FillRectangle(new SolidBrush(Color.FromArgb(80, 255, 0, 0)), Left, Top, size.Width, size.Height);

            return false; 
        }

        private void ExcelButton_Click(object sender, EventArgs e)
        {
            if (AnalysisTable.Rows.Count == 0)
            {
                MessageBox.Show("Select configuration for analysis");

                return;
            }

            if (!File.Exists("Templates\\Analysis.xls"))
            {
                MessageBox.Show("Template Analysis.xls not found");

                return;
            }

            try
            {
                ExcelManager excelManager = new ExcelManager();

                excelManager.Open("Templates\\Analysis.xls");

                DBManager.Open();

                string[][] Data = DBManager.ExecuteReader("SELECT Configurations.[Name], Servers.[Name] FROM Objects Configurations, Links, Objects Servers WHERE Configurations.ID = Links.ObjectID AND Servers.ID = Links.ID AND Configurations.ID = " + ConfigurationID);

                DBManager.Close();

                excelManager.EditCell(1, 1, "Analysis of the " + Data[0][0] + " configuration for " + Data[0][1]);

                excelManager.EditCell(2, 9, DateTime.Now.ToShortDateString());

                for (int j = 0; j < AnalysisTable.Rows.Count; j++)
                {
                    for (int i = 0; i < 9; i++)
                    {
                        if (j != AnalysisTable.Rows.Count - 1)
                        {
                            excelManager.InsertCell(j + 5, i + 1);
                        }

                        if (AnalysisTable[i + 1, j].Value != null)
                        {
                            excelManager.EditCell(j + 5, i + 1, AnalysisTable[i + 1, j].Value.ToString());
                        }

                        if (j == AnalysisTable.Rows.Count - 1)
                        {
                            excelManager.DeleteCell(4, i + 1);
                        }
                    }
                }

                excelManager.EditCell(AnalysisTable.Rows.Count + 8, 1, ParametersTable[0, 0].Value.ToString());
                excelManager.EditCell(AnalysisTable.Rows.Count + 8, 2, ParametersTable[1, 0].Value.ToString());
                excelManager.EditCell(AnalysisTable.Rows.Count + 8, 3, ParametersTable[2, 0].Value.ToString());
                excelManager.EditCell(AnalysisTable.Rows.Count + 8, 4, ParametersTable[3, 0].Value.ToString());
                excelManager.EditCell(AnalysisTable.Rows.Count + 8, 5, ParametersTable[4, 0].Value.ToString());

                excelManager.Display();
            }
            catch (Exception ex)
            {
                MessageBox.Show("MS Office Excel open error");
            }
        }

        private void ImagePanel_Paint(object sender, PaintEventArgs e)
        {
            ImageBuffer.Render();
            ImageBuffer.Render(ImagePanel.CreateGraphics());
        }

        private void PrintButton_Click(object sender, EventArgs e)
        {
            try
            {
                PrintDialog printDialog = new PrintDialog();

                print = new Bitmap(1200, 800);

                int leftmargin = (1200 - (AnalysisTable.Width + 15)) / 2;
                int topmargin = (800 - (AnalysisTable.Height + 15)) / 2;

                Graphics gbmp = Graphics.FromImage(print);
                gbmp.Clear(Color.White);
                gbmp.CopyFromScreen(SplitContainer.Panel2.Left + 20, SplitContainer.Top + 15, leftmargin, topmargin - 20, new Size(AnalysisTable.Width + 15, AnalysisTable.Height + 20));
                
                //if (AnalysisTable.Width > 1000 || AnalysisTable.Height > 700)
                //{
                //    print = new Bitmap(print, new Size((int)(AnalysisTable.Width * (1000.0 / AnalysisTable.Width)), (int)((AnalysisTable.Height + 15) * (1000.0 / AnalysisTable.Width))));
                //}

                DBManager.Open();

                string[][] Data = DBManager.ExecuteReader("SELECT Configurations.[Name], Servers.[Name] FROM Objects Configurations, Links, Objects Servers WHERE Configurations.ID = Links.ObjectID AND Servers.ID = Links.ID AND Configurations.ID = " + ConfigurationID);

                DBManager.Close();

                Font font12 = new Font("Book Antiqua", 12.0f);
                Font font14 = new Font("Book Antiqua", 14.0f);
                string Title = "Analysis of the " + Data[0][0] + " configuration for " + Data[0][1];
                SizeF sizef14 = gbmp.MeasureString(Title, font14);
                gbmp.DrawString(Title, font14, new SolidBrush(Color.Black), new PointF((print.Width - sizef14.Width) / 2, topmargin - 90));
                gbmp.DrawString(DateTime.Now.ToShortDateString(), new Font("Book Antiqua", 14), new SolidBrush(Color.Black), new PointF(print.Width - 100 - leftmargin, topmargin - 60));

                gbmp.DrawString("The probability of a server failure during the year: " + ParametersTable[0, 0].Value.ToString(), font12, new SolidBrush(Color.Black), new PointF(leftmargin + 10, 800 - topmargin - 10));
                gbmp.DrawString("MTBF ot the server: " + ParametersTable[1, 0].Value.ToString() + " years", font12, new SolidBrush(Color.Black), new PointF(leftmargin + 10, 800 - topmargin + 10));
                gbmp.DrawString("The average time troubleshooting: " + ParametersTable[2, 0].Value.ToString() + " hours", font12, new SolidBrush(Color.Black), new PointF(leftmargin + 10, 800 - topmargin + 30));
                gbmp.DrawString("Average failure time in a year: " + ParametersTable[3, 0].Value.ToString() + " hours", font12, new SolidBrush(Color.Black), new PointF(leftmargin + 10, 800 - topmargin + 50));
                gbmp.DrawString("Server availability: " + ParametersTable[4, 0].Value.ToString(), font12, new SolidBrush(Color.Black), new PointF(leftmargin + 10, 800 - topmargin + 70));
                
                if (printDialog.ShowDialog() == DialogResult.OK)
                {
                    PrintDocument document = new PrintDocument();

                    document.DefaultPageSettings.Landscape = true;

                    document.PrintPage += new PrintPageEventHandler(document_PrintPage);

                    document.Print();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Printer error");
            }
        }

        void document_PrintPage(object sender, PrintPageEventArgs e)
        {
            e.Graphics.DrawImage(print, new Point(0, 0));

            e.HasMorePages = false;
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            ImagePanel.Width = ImageCanvas.Width - 5;
            ImagePanel.Height = ImageCanvas.Height - 5;

            FormLogin formLogin = new FormLogin();

            if (formLogin.ShowDialog() == DialogResult.Abort || formLogin.Rights == 0)
            {
                Close();
            }
            else
            {
                if (formLogin.Rights == 2)
                {
                    Rights = formLogin.Rights;                    
                }
            }
        }
    }
}
